// 引入必要的模块
const express = require('express');
const mysql = require('mysql');
const bodyParser = require('body-parser');
const session = require('express-session');
const fs = require('fs');
const ejs = require('ejs');
const path = require('path');


// 创建数据库连接
const connection = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: '123456',
    database: 'user'
});

//判断数据库是否连接成功
connection.connect(function(err){
    // 判断连接数据库时是否发生错误
    if(err){
         // 如果有错误，打印出错误信息
        console.log('[query] - :'+err);
         return;
    }
    // 如果没有发生错误，打印连接成功的信息
    console.log('MySQL数据库连接成功!');
});

//创建服务器
var app = express();
app.use(bodyParser.urlencoded({
     extended: false
}));
// 使用body-parser中间件来解析请求体
app.use(bodyParser.urlencoded({ extended: false }));

// 设置更安全的session中间件的secret密钥，替换示例密钥没有就不会实现跳转
app.use(session({
    secret: process.env.SESSION_SECRET || 'a_very_secure_secret_key', // 优先从环境变量获取，没有则使用默认值
    resave: false,
    saveUninitialized: true
}));

// 配置静态文件中间件，指向存放HTML等静态文件的目录
app.use(express.static('D:\\20221613516\\user'));

// 处理GET请求，返回登录页面（利用静态文件中间件）
app.get('/login', function (req, res) {
    res.sendFile('login.html', { root: 'D:\\20221613516\\user' });
});

// 处理POST请求，验证登录信息，依据MySQL数据库内容进行验证，并在失败时返回登录页面展示错误提示
app.post('/login', function (req, res) {
  let username = req.body.username;
  let password = req.body.password;

  // 查询数据库以验证用户，使用参数化查询防止SQL注入
  let sql = 'SELECT * FROM users WHERE username = ? AND password = ?';
  //与 MySQL 数据库交互的函数。它执行 SQL 查询并返回结果。 
    connection.query(sql, [username, password], function (err, results) {  
        if (err) {  
            //打印错误信息
            console.error('Error querying database: ' + err.stack);  
            res.writeHead(500, { 'Content-Type': 'text/html' });  
            res.end('<h1>内部服务器错误</h1>');  
            return;  
        }  
        if (results.length > 0) {  
          // 用户存在，登录成功，将用户信息存储到 session 中
          req.session.user = { username: username };  
          // 重定向到用户个人中心页面
          res.redirect('/list');
      } else {
          // 用户不存在或密码错误，返回登录页面并传递错误提示信息，通过查询字符串的error参数传递错误内容
          res.sendFile('login.html', {
              root: 'D:\\20221613516\\user',
              query: { error: '用户名或密码错误，请重新输入' }
          });
      }
  });
});

// 处理GET请求，返回注册页面（利用静态文件中间件）
app.get('/register', function (req, res) {
    res.sendFile('register.html', { root: 'D:\\20221613516\\user' });
});

// 处理POST请求，处理注册表单
app.post('/register', function (req, res) {
    // 获取请求体中的用户名
    let username = req.body.username;
    // 获取请求体中的密码
    let password = req.body.password;

    // 检查用户名是否已存在
    let checkSql = 'SELECT * FROM users WHERE username =?';
    connection.query(checkSql, [username], function (err, results) {
        if (err) {
            // 打印错误信息
            console.error('Error querying database: ' + err.stack);
            // 设置响应头，500表示服务器内部错误
            res.writeHead(500, { 'Content-Type': 'text/html' });
            // 返回提示信息
            res.end('<h1>内部服务器错误</h1>');
            return;
        }
        // 如果查询结果长度大于0，表示用户名已经存在
        if (results.length > 0) {
            // 设置响应头，200表示请求成功
            res.writeHead(200, { 'Content-Type': 'text/html' });
            // 返回用户名已存在的提示信息
            res.end('<h1>用户名已存在</h1>');
        } else {
            // 插入新用户
            let insertSql = 'INSERT INTO users (username, password) VALUES (?,?)';
            connection.query(insertSql, [username, password], function (err, results) {
                if (err) {
                    console.error('Error inserting into database: ' + err.stack);
                    res.writeHead(500, { 'Content-Type': 'text/html' });
                    res.end('<h1>Internal Server Error</h1>');
                    return;
                }
                // 注册成功，重定向到登录页面
                res.redirect('/login');
            });
        }
    });
});

// 处理GET请求，进入预约教室页面
app.get('/list', function (req, res) {
    // 检查用户是否已经登录（通过 session 中是否存在用户信息判断）
    if (!req.session.user) {
        // 用户未登录，重定向到登录页面
        return res.redirect('/login');
    }

    // 读取模板文件，此处可考虑添加缓存机制避免频繁读取文件，提升性能
    fs.readFile('list.html', 'utf8', function (error, data) {
        // 如果读取过程中发生错误，则通过回调函数的 'error' 参数来处理错误
        if (error) {
            // 如果出现错误，打印错误信息并响应 500 错误
            console.error('Error reading template file: ' + error.stack);
            return res.status(500).send('<h1>内部服务器错误</h1>');
        }

        // 如果文件读取成功，执行SQL语句，查询约教室数据
        const sql = 'SELECT * FROM registered';
        // queryDB 函数负责执行数据库查询
        // 如果查询数据库时发生错误，回调中的 'error' 参数会返回错误信息
        queryDB(sql, [], function (error, results) {  
            if (error) {
                console.error('Error querying database: ' + error.stack);
                return res.status(500).send('<h1>内部服务器错误</h1>');
            }

            // 使用 ejs 渲染引擎渲染 HTML 模板，并传递从数据库查询到的结果和用户名数据
            res.send(ejs.render(data, {
                // 将数据库查询结果传递到模板中，模板可以访问 'data' 数据
                data: results,
                // 获取当前会话中存储的用户名信息，传递给模板
                username: req.session.user.username
            }));
        });
    });
});

// 处理GET请求，实现用户登出功能（清除 session 中的用户信息）
app.get('/logout', function (req, res) {
    // 销毁会话
    req.session.destroy(function (err) {
        // 如果销毁会话时发生错误
        if (err) {
            console.error('Error destroying session: ', err);
            res.writeHead(500, { 'Content-Type': 'text/html' });
            res.end('<h1>Internal Server Error</h1>');
        } else {
            // 登出成功，重定向到登录页面
            res.redirect('/login');
        }
    });
});

// 根路由重定向到登录页面
app.get('/', function (req, res) {
    res.redirect('/login');
});

// 启动服务器
app.listen(3516, function () {
    console.log('Server running at http://127.0.0.1:3516');
});

//显示学生列表
app.get('/list', function (request, response) {
     //读取模板文件
     fs.readFile('list.html', 'utf8', function (error, data) {
          //执行SQL语句
          connection.query('select * from registered', function (error, results) {
               //响应信息
               response.send(ejs.render(data, {
                     data: results
               }));
          });
     });
});

//添加数据
app.get('/insert', function (request, response) {
    //读取模板文件
    fs.readFile('insert.html', 'utf8', function (error, data) {
         //响应信息
         response.send(data);
    });
});
app.post('/insert', function (request, response) {
    //声明body
    var body = request.body;
    //执行SQL语句
    connection.query('insert into registered (username, classroom, date) VALUES (?, ?, ?)', [
         body.username, body.classroom, body.date
    ], function () {
         //响应信息
         response.redirect('/list');
    });
});

//修改数据
app.get('/edit/:id', function (request, response) {
    //读取模板文件
    fs.readFile('edit.html', 'utf8', function (error, data) {
         //执行SQL语句
         connection.query('select * from registered where id = ?', [
              request.params.id
         ], function (error, result) {
              //响应信息
              response.send(ejs.render(data, {
                    data: result[0]
              }));
         });
    });
});

// 定义一个处理POST请求的路由，用于编辑信息
app.post('/edit/:id', function (request, response) {
    // 声明一个变量body，用于存储请求体中的数据
    var body = request.body;
    // 执行SQL语句，更新registered表中指定id的学生信息
    connection.query('update registered set username=?, classroom=?, date=? where id=?',
       // 将请求体中的name、number、score和路由参数中的id作为更新的值
       [body.username, body.classroom, body.date, request.params.id], function () {
         // 响应信息，重定向到/list页面
         response.redirect('/list');
    });
});

//删除数据
app.get('/delete/:id', function (request, response) {
    //执行SQL语句
    connection.query('delete from registered where id=?', [request.params.id], function () {
         //响应信息
         response.redirect('/list');
    });
});


// 设置视图引擎为 ejs
app.set('view engine', 'ejs');

// 设置视图文件所在目录
app.set('views', path.join(__dirname, 'views'));
//查询数据
app.get('/search', function (request, response) {
    // 从请求中获取查询参数 (username, classroom, date)
    // 这些参数将用于过滤数据库中的数据
    const { username, classroom, date } = request.query;
    
    // 初始化 SQL 查询语句，'1=1' 是一个始终为真的条件，用于方便拼接后续条件
    let query = 'SELECT * FROM registered WHERE 1=1';
    // 创建一个空数组，用于存储查询条件的值
    let queryParams = [];

    // 如果有提供查询条件，则动态地拼接到 SQL 语句中
    if (username) {
        // 将 'username' 作为模糊查询条件添加到 SQL 语句
        query += ' AND username LIKE ?';
        // 使用 '%' 进行模糊匹配，表示查找包含 'username' 的记录
        queryParams.push(`%${username}%`); // 使用LIKE进行模糊匹配
    }
    if (classroom) {
        query += ' AND classroom LIKE ?';
        queryParams.push(`%${classroom}%`);
    }
    if (date) {
        // 将 'date' 作为精确匹配条件添加到 SQL 语句
        query += ' AND date = ?';
        // 这里直接将日期值添加到查询参数中，进行精确匹配
        queryParams.push(date);
    }

    // 执行查询
    connection.query(query, queryParams, function (error, result) {
         // 如果查询失败，打印错误信息并返回 500 状态码，表示服务器错误
        if (error) {
            console.error('查询失败:', error);
            return response.status(500).send('查询失败');
        }

        // 查询成功后，将查询结果 'result' 渲染到模板 'searchResults' 中
        response.render('searchResults', {
            data: result
        });
    });
});


// 封装数据库查询操作函数，减少重复代码并增强可读性
function queryDB(sql, values, callback) {
    connection.query(sql, values, function (err, results) {
        if (err) {
            console.error('Error querying database: ' + err.stack);
            callback(err);
            return;
        }
        callback(null, results);
    });
}
